package com.tj.seed.common.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.tj.seed.common.constant.ResultCode;
import com.tj.seed.common.context.UserContext;
import com.tj.seed.common.domain.Result;
import org.springframework.stereotype.Service;

@Service
public class TokenParserImpl extends JwtBase implements TokenParser {
    private final Algorithm algorithm;
    private final String issuer;

    public TokenParserImpl(Algorithm algorithm, String issuer) {
        this.algorithm = algorithm;
        this.issuer = issuer;
    }

    @Override
    public Result<UserContext> verify(String token) {
        JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer(issuer)
                .build();
        DecodedJWT decodedJWT = null;
        try {
            decodedJWT = verifier.verify(token);
        } catch (TokenExpiredException e) {
            return Result.fail(ResultCode.AUTH_NO_VALID_TOKEN);
        } catch (JWTVerificationException e) {
            return Result.fail(ResultCode.AUTH_NO_VALID_TOKEN);
        }
        return Result.success(getClaim(decodedJWT));
    }

    @Override
    public Result<UserContext> parse(String token) {
        DecodedJWT decodedJWT = JWT.decode(token);
        return Result.success().setData(getClaim(decodedJWT));
    }

    protected UserContext getClaim(DecodedJWT decodedJWT) {
        UserContext userContext = new UserContext();
        userContext.setUserId(decodedJWT.getClaim(USER_ID_KEY).asLong());
        Claim claim = decodedJWT.getClaim(LOGIN_ID_KEY);
        if (claim != null) {
            userContext.setLoginName(claim.asString());
        }
        claim = decodedJWT.getClaim(USER_NAME_KEY);
        if (claim != null) {
            userContext.setUserName(claim.asString());
        }
        return userContext;
    }
}
